#include "ME2NetFolder.h"

int ME2NetFolder::UploadFile(LPCSTR file, LPCSTR parent, LPCSTR name, int unzip/*=0*/) 
{
	CLStr cmd, dst;
	struct stat st;

	if(!CheckFolderPath(parent)) return 1;
	if(!CheckFolderName(name)) return 2;
	if(unzip && strcasestr(file, ".zip")) {
		cmd.sprintf("unzip '%s' -d '%s%s'", file, (LPCSTR)m_root, parent);
		system(cmd);
	}
	dst.sprintf("%s%s%s", (LPCSTR)m_root, parent, name);
	if(stat(dst, &st) == 0) dst.sprintf("%s%s2%s", (LPCSTR)m_root, parent, name);
	cmd.sprintf("mv '%s' '%s'", file, (LPCSTR)dst);
	system(cmd);
	return 0;			
}
int ME2NetFolder::GetAllFolder(LPCSTR parent,CLStrList& folderList) {
        struct dirent *dp;      
        DIR *dirp;
	CLStr folder;
	
	folderList.append(parent);

	folder.sprintf("%s%s", (LPCSTR)m_root, parent);
        if(!(dirp=opendir(folder))) return 0;
        while((dp=readdir(dirp))) {
        	if(dp->d_name[0] == '.') continue;
        	if(dp->d_type & DT_DIR) {
        		folder.sprintf("%s%s/", parent, dp->d_name);
        		GetAllFolder((LPCSTR)folder, folderList);
        	}
        }
        closedir(dirp);
        
        return 1;
}

int cmp_name(const void* a, const void* b) {
	return strcmp(LPCSTR((*(FileInfo**)a)->name),LPCSTR((*(FileInfo**)b)->name));	
}
int cmp_size(const void* a, const void* b) {
	return (*(FileInfo**)a)->size-(*(FileInfo**)b)->size;
}
int cmp_time(const void* a, const void* b) {
	return (*(FileInfo**)a)->time-(*(FileInfo**)b)->time;
}
int cmp_name_desc(const void* a, const void* b) {
	return -cmp_name(a, b);
}
int cmp_size_desc(const void* a, const void* b) {
	return -cmp_size(a, b);
}
int cmp_time_desc(const void* a, const void* b) {
	return -cmp_time(a, b);
}
int ME2NetFolder::NewFolder(LPCSTR parent, LPCSTR folder) {
	if(!CheckFolderPath(parent)) return 1;
	if(!CheckFolderName(folder)) return 2;
	if(!IsFolder(parent)) return 3;
	CLStr f;
	f.sprintf("%s%s%s", (LPCSTR)m_root, parent, folder);
	if(f.length()>1000) return 4;
	return mkdir(f, 0755);
}
int ME2NetFolder::Rename(CLStr& fid, LPCSTR dst) 
{
	if(!CheckFolderPath(fid)) return 1;
	if(!CheckFolderName(dst)) return 2;
	CLStr f1, f2;
	f1.sprintf("%s%s", (LPCSTR)m_root, (LPCSTR)fid);
	f2.sprintf("%s%s", (LPCSTR)m_root, LPCSTR(FolderParent(fid) + dst));
	return rename(f1, f2);
}
int ME2NetFolder::Move(CLStr fid, CLStr dst, int bToOut/*=0*/)
{
	if(!CheckFolderPath(fid)) return 1;
	if(!CheckFolderPath(dst)) return 2;
	if(!bToOut) dst = m_root + dst;
	CLStr cmd;
	cmd.sprintf("mv '%s%s' '%s'", (LPCSTR)m_root, (LPCSTR)fid, (LPCSTR)dst);
	system(cmd);	
	return 0;
}
int ME2NetFolder::Copy(CLStr fid, LPCSTR dst)
{
	if(!CheckFolderPath(fid)) return 1;
	if(!CheckFolderPath(dst)) return 2;
	CLStr cmd;
	cmd.sprintf("cp '%s%s' '%s%s'", (LPCSTR)m_root, (LPCSTR)fid, (LPCSTR)m_root, dst);
	system(cmd);	
	return 0;
}
int ME2NetFolder::Del(CLStr fid)
{
	if(!CheckFolderPath(fid)) return 1;
	if(IsFolder(fid)) {
		CLStr cmd;
		cmd.sprintf("rm -fr '%s%s'", (LPCSTR)m_root, (LPCSTR)fid);
		system(cmd);
		return 0;
	} else return unlink(AbsolutePath(fid));
}
CLStr ME2NetFolder::FolderParent(CLStr& fid) 
{
	if(fid != "/") {
		CLStr fid2 = fid.substr(0, fid.length()-1);
		return fid2.substr(0, fid2.rfind("/")+1);
	} else return fid;
}
int ME2NetFolder::IsFolder(LPCSTR folder) {
	struct stat st;
	CLStr f;
	f.sprintf("%s%s", (LPCSTR)m_root, folder);
	if(stat(f,&st) == 0 && S_ISDIR(st.st_mode)) return 1;
	return 0;		
}
int ME2NetFolder::CheckFolderPath(LPCSTR path) {
	CLStr p;
	if(path[0]=='/') path++;
	p = path;
	CLStrList path_list;
	p.split("/", path_list, 1);
	for(int i=0;i<path_list.length();i++) {
		if((path_list[i].empty() && i==0)||!CheckFolderName(path_list[i])) return 0;
	}
	return 1;
} 
int ME2NetFolder::CheckFolderName(LPCSTR folder) {
	char* f = (char*)folder;
	while(*f) {
		if((*f>='a' && *f <='z')
		  ||(*f>='A' && *f <='Z')
		  ||(*f>='0' && *f <='9')
		  || *f<0 || *f == ' '
		  || *f == '.' || *f == '+' || *f == '_' || *f == '-'
		  || *f == '!' || *f == '#' || *f == '$'
		  || *f == '(' || *f == ')' || *f == '[' || *f == ']') {}
		else return 0;
		f++;
	}
	if(f - (char*)folder > 98) return 0;
	if(strstr(folder, "..") || folder[0]=='.') return 0;
	return 1;
}
int ME2NetFolder::Open(LPCSTR path, int bCreate/*=0*/)
{ 
	m_root = path; 
	m_root+="/Netdir"; 
	if(IsFolder("/")) return 1;
	if(bCreate) mkdir(m_root, 0755);
	return 0;
}	
unsigned long ME2NetFolder::Size(LPCSTR fid) {
	struct stat st;
	int num_file, num_folder;
	if(!CheckFolderName(fid) || stat(m_root+fid, &st)) return 0;
	if(S_ISDIR(st.st_mode)) return GetFolderProps(fid, &num_file, &num_folder);
	else return st.st_size;
}
unsigned long ME2NetFolder::GetFolderProps(LPCSTR parent, int* num_file, int* num_folder/*=NULL*/) 
{
        struct dirent *dp;      
        DIR *dirp;
	CLStr folder,f;
	struct stat st;
	unsigned long size = 0;
	
	folder.sprintf("%s%s", (LPCSTR)m_root, parent);
        if(!(dirp=opendir(folder))) return 0;
        while((dp=readdir(dirp))) {
        	if(dp->d_name[0] == '.') continue;
        	if(dp->d_type & DT_DIR) {
        		if(num_folder) {
        			(*num_folder)++;
        			f.sprintf("%s%s/", parent, dp->d_name);
        			size += GetFolderProps(LPCSTR(f), num_file, num_folder);
        		}
        	} else if(stat(folder+dp->d_name, &st)==0) {
        		size += st.st_size;
        		(*num_file)++;
		}
	}
        closedir(dirp);
	return size;
}

int ME2NetFolder::GetFolderFile(LPCSTR parent, CLPtrList& folderList, CLPtrList& fileList, int (*cb)(const void*a, const void*b)) 
{
        struct dirent *dp;      
        DIR *dirp;
	CLStr folder;
	FileInfo* fi;
	struct stat st;
	char* ext;
	
	folder.sprintf("%s%s", (LPCSTR)m_root, parent);
        if(!(dirp=opendir(folder))) return 0;
        while((dp=readdir(dirp))) {
        	if(dp->d_name[0] == '.') continue;
        	if(dp->d_type & DT_DIR) {
			fi = (FileInfo*)malloc(sizeof(FileInfo));
			strncpy(fi->name,dp->d_name,100);
			fi->type[0] = '\0';
			fi->size = 0;
			fi->time = 0;
			fi->parent[0] = '\0';
        		folderList.append(fi);
        	} else if(stat(folder+dp->d_name, &st)==0) {
			fi = (FileInfo*)malloc(sizeof(FileInfo));
			strncpy(fi->name, dp->d_name, 100);
			if((ext = strrchr(dp->d_name, '.'))) strncpy(fi->type, ext+1, 40);
			else fi->type[0] = '\0';
			fi->size = st.st_size;
			fi->time = st.st_ctime;
			fi->parent[0] = '\0';
			fileList.append(fi);
		}
	}
        closedir(dirp);

        if(cb) {
        	folderList.sort(cb);
        	fileList.sort(cb);
        }
        return 1;
}
const char* nf_mime_type[] = { 	NULL,
				"gif jpg jpeg png bmp",
				"mp3 wav wma"
				"wmv asf rm"
			      };
int ME2NetFolder::SearchFolder(LPCSTR parent, FileSearch* fs, CLPtrList& folderList, CLPtrList& fileList) 
{
        struct dirent *dp;      
        DIR *dirp;
	CLStr folder,str;
	FileInfo* fi;
	struct stat st;
	char* ext;
	
	folder.sprintf("%s%s", (LPCSTR)m_root, parent);
        if(!(dirp=opendir(folder))) return 0;
        while((dp=readdir(dirp))) {
        	if(dp->d_name[0] == '.') continue;
        	if(dp->d_type & DT_DIR) {
			fi = (FileInfo*)malloc(sizeof(FileInfo));
			strncpy(fi->name,dp->d_name,100);
			fi->type[0] = '\0';
			fi->size = 0;
			fi->time = 0;
			strncpy(fi->parent, parent, 1024);
        		folderList.append(fi);
        		if(fs->recursive) SearchFolder(str.sprintf("%s%s/", parent, dp->d_name), fs, folderList, fileList);
        	} else if(stat(folder+dp->d_name, &st)==0) {
        		ext = strrchr(dp->d_name, '.');
        		if( (fs->time_from == 0 || st.st_ctime > fs->time_from)
        		  &&(fs->time_to   == 0 || st.st_ctime < fs->time_to)
        		  &&(fs->size_from == 0 || st.st_size  > fs->size_from)
        		  &&(fs->size_to   == 0 || st.st_size  < fs->size_to)
        		  &&(!fs->keyword||!*(fs->keyword) || (fs->kwcase && strstr(dp->d_name, fs->keyword)) || (!fs->kwcase && strcasestr(dp->d_name, fs->keyword)))
        		  &&(!ext || (fs->type<NF_MIME_TYPE_MIN||fs->type>NF_MIME_TYPE_MAX) || strstr(nf_mime_type[fs->type], ext+1))
        		) {
				fi = (FileInfo*)malloc(sizeof(FileInfo));
				strncpy(fi->name, dp->d_name, 100);
				if(ext) strncpy(fi->type, ext+1, 40);
				else fi->type[0] = '\0';
				fi->size = st.st_size;
				fi->time = st.st_ctime;
				strncpy(fi->parent, parent, 1024);
				fileList.append(fi);
			}
		}
	}
        closedir(dirp);

        return 1;
}
